package me.illtamer.rpc.transport;

import me.illtamer.rpc.annotation.Service;
import me.illtamer.rpc.annotation.ServiceScan;
import me.illtamer.rpc.enumeration.RpcError;
import me.illtamer.rpc.exception.RpcException;
import me.illtamer.rpc.provider.ServiceProvider;
import me.illtamer.rpc.register.ServiceRegistry;
import me.illtamer.rpc.util.ReflectUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.InetSocketAddress;
import java.util.Set;

/**
 * 扫描服务类并进行服务注册
 * */

public abstract class AbstractRpcServer implements RpcServer {

    protected final Logger log = LoggerFactory.getLogger(AbstractRpcServer.class);

    protected String host;
    protected int port;
    protected ServiceRegistry serviceRegistry;
    protected ServiceProvider serviceProvider;

    public void scanServices() {
        String mainClassName = ReflectUtil.getStackTrace();
        Class<?> startClass;
        try {
            startClass = Class.forName(mainClassName);
            if (!startClass.isAnnotationPresent(ServiceScan.class)) {
                log.error("启动类缺少 @ServiceScan 注解");
                throw new RpcException(RpcError.SERVICE_SCAN_PACKAGE_NOT_FOUND);
            }
        } catch (ClassNotFoundException e) {
            log.info("出现未知错误");
            throw new RpcException(RpcError.UNKNOWN_ERROR);
        }
        String basePackage = startClass.getAnnotation(ServiceScan.class).value();
        if (basePackage.length() == 0) {
            // 获取启动类所在的包，因为服务类也放在这个包下面的
            basePackage = mainClassName.substring(0, mainClassName.lastIndexOf("."));
        }
        Set<Class<?>> classSet = ReflectUtil.getClasses(basePackage);
        for (Class<?> clazz : classSet) {
            if (!clazz.isAnnotationPresent(Service.class)) continue;
            String serviceName = clazz.getAnnotation(Service.class).name();
            Object object;
            try {
                object = clazz.newInstance();
            } catch (IllegalAccessException | InstantiationException e) {
                log.error("创建 {} 时有错误发生", clazz);
                continue;
            }
            if (serviceName.length() == 0) {
                // 一个服务 Impl 类可能实现类多个服务接口
                Class<?>[] interfaces = clazz.getInterfaces();
                for (Class<?> _interface : interfaces) {
                    publishService(object, _interface.getCanonicalName());
                }
            } else {
                publishService(object, serviceName);
            }
        }
    }

    @Override
    public <T> void publishService(T service, String serviceName) {
        serviceProvider.addServiceProvider(service, serviceName);
        serviceRegistry.register(serviceName, new InetSocketAddress(host, port));
    }

}
